<template>
  <main class="threejs-demo">
    <h1 class="section-title">Three.js 特性演示</h1>
    
    <section class="demo-grid">
      <!-- 基础几何体 -->
      <article class="demo-card">
        <header class="demo-header">
          <h2>基础几何体</h2>
          <button @click="showCode('geometry')" class="code-btn" aria-label="查看基础几何体代码">查看代码</button>
        </header>
        <div class="demo-content">
          <div class="canvas-container" ref="basicGeometryContainer" role="img" aria-label="基础几何体演示"></div>
          <nav class="controls">
            <button @click="changeGeometry('box')" aria-label="切换到立方体">立方体</button>
            <button @click="changeGeometry('sphere')" aria-label="切换到球体">球体</button>
            <button @click="changeGeometry('torus')" aria-label="切换到圆环">圆环</button>
          </nav>
        </div>
      </article>

      <!-- 材质效果 -->
      <article class="demo-card">
        <header class="demo-header">
          <h2>材质效果</h2>
          <button @click="showCode('material')" class="code-btn" aria-label="查看材质效果代码">查看代码</button>
        </header>
        <div class="demo-content">
          <div class="canvas-container" ref="materialsContainer" role="img" aria-label="材质效果演示"></div>
          <nav class="controls">
            <button @click="changeMaterial('standard')" aria-label="切换到标准材质">标准材质</button>
            <button @click="changeMaterial('phong')" aria-label="切换到Phong材质">Phong材质</button>
            <button @click="changeMaterial('toon')" aria-label="切换到卡通材质">卡通材质</button>
          </nav>
        </div>
      </article>

      <!-- 光照效果 -->
      <article class="demo-card">
        <header class="demo-header">
          <h2>光照效果</h2>
          <button @click="showCode('light')" class="code-btn" aria-label="查看光照效果代码">查看代码</button>
        </header>
        <div class="demo-content">
          <div class="canvas-container" ref="lightsContainer" role="img" aria-label="光照效果演示"></div>
          <nav class="controls">
            <button @click="changeLight('point')" aria-label="切换到点光源">点光源</button>
            <button @click="changeLight('spot')" aria-label="切换到聚光灯">聚光灯</button>
            <button @click="changeLight('ambient')" aria-label="切换到环境光">环境光</button>
          </nav>
        </div>
      </article>

      <!-- 动画效果 -->
      <article class="demo-card">
        <header class="demo-header">
          <h2>动画效果</h2>
          <button @click="showCode('animation')" class="code-btn" aria-label="查看动画效果代码">查看代码</button>
        </header>
        <div class="demo-content">
          <div class="canvas-container" ref="animationContainer" role="img" aria-label="动画效果演示"></div>
          <nav class="controls">
            <button @click="toggleAnimation">{{ isAnimating ? '暂停' : '播放' }}</button>
            <button @click="resetAnimation" aria-label="重置动画">重置</button>
          </nav>
        </div>
      </article>

      <!-- 相机控制 -->
      <article class="demo-card">
        <header class="demo-header">
          <h2>相机控制</h2>
          <button @click="showCode('camera')" class="code-btn" aria-label="查看相机控制代码">查看代码</button>
        </header>
        <div class="demo-content">
          <div class="canvas-container" ref="cameraControlContainer" role="img" aria-label="相机控制演示"></div>
          <nav class="controls">
            <button @click="changeCamera('perspective')" aria-label="切换到透视相机">透视相机</button>
            <button @click="changeCamera('orthographic')" aria-label="切换到正交相机">正交相机</button>
            <button @click="toggleCameraAnimation">{{ isCameraAnimating ? '暂停' : '播放' }}</button>
          </nav>
        </div>
      </article>

      <!-- 后期处理 -->
      <article class="demo-card">
        <header class="demo-header">
          <h2>后期处理</h2>
          <button @click="showCode('postprocessing')" class="code-btn" aria-label="查看后期处理代码">查看代码</button>
        </header>
        <div class="demo-content">
          <div class="canvas-container" ref="postProcessingContainer" role="img" aria-label="后期处理演示"></div>
          <nav class="controls">
            <button @click="changeEffect('none')" aria-label="切换到无效果">无效果</button>
            <button @click="changeEffect('bloom')" aria-label="切换到辉光">辉光</button>
            <button @click="changeEffect('outline')" aria-label="切换到描边">描边</button>
          </nav>
        </div>
      </article>

      <!-- 粒子系统 -->
      <article class="demo-card">
        <header class="demo-header">
          <h2>粒子系统</h2>
          <button @click="showCode('particles')" class="code-btn" aria-label="查看粒子系统代码">查看代码</button>
        </header>
        <div class="demo-content">
          <div class="canvas-container" ref="particlesContainer" role="img" aria-label="粒子系统演示"></div>
          <nav class="controls">
            <button @click="changeParticleType('points')" aria-label="切换到点粒子">点粒子</button>
            <button @click="changeParticleType('sprites')" aria-label="切换到精灵粒子">精灵粒子</button>
            <button @click="toggleParticleAnimation">{{ isParticleAnimating ? '暂停' : '播放' }}</button>
          </nav>
        </div>
      </article>

      <!-- 物理效果 -->
      <article class="demo-card">
        <header class="demo-header">
          <h2>物理效果</h2>
          <button @click="showCode('physics')" class="code-btn" aria-label="查看物理效果代码">查看代码</button>
        </header>
        <div class="demo-content">
          <div class="canvas-container" ref="physicsContainer" role="img" aria-label="物理效果演示"></div>
          <nav class="controls">
            <button @click="addPhysicsObject('sphere')" aria-label="添加球体">添加球体</button>
            <button @click="addPhysicsObject('box')" aria-label="添加立方体">添加立方体</button>
            <button @click="resetPhysics" aria-label="重置物理效果">重置</button>
          </nav>
        </div>
      </article>

      <!-- 音频可视化 -->
      <article class="demo-card">
        <header class="demo-header">
          <h2>音频可视化</h2>
          <button @click="showCode('audio')" class="code-btn" aria-label="查看音频可视化代码">查看代码</button>
        </header>
        <div class="demo-content">
          <div class="canvas-container" ref="audioContainer" role="img" aria-label="音频可视化演示"></div>
          <div class="audio-upload">
            <input 
              type="file" 
              accept="audio/*" 
              @change="handleAudioUpload" 
              ref="audioInput"
              class="audio-input"
              aria-label="选择音频文件"
            >
            <button @click="triggerAudioUpload" class="upload-btn" aria-label="选择音频文件">选择音频文件</button>
          </div>
          <nav class="controls">
            <button @click="toggleAudio" :disabled="!audioSource">{{ isAudioPlaying ? '暂停' : '播放' }}</button>
            <button @click="changeAudioVisualization('bars')" :disabled="!audioSource" aria-label="切换到频谱柱状">频谱柱状</button>
            <button @click="changeAudioVisualization('circle')" :disabled="!audioSource" aria-label="切换到圆形频谱">圆形频谱</button>
          </nav>
        </div>
      </article>

      <!-- 着色器效果 -->
      <article class="demo-card">
        <header class="demo-header">
          <h2>着色器效果</h2>
          <button @click="showCode('shader')" class="code-btn" aria-label="查看着色器效果代码">查看代码</button>
        </header>
        <div class="demo-content">
          <div class="canvas-container" ref="shaderContainer" role="img" aria-label="着色器效果演示"></div>
          <nav class="controls">
            <button @click="changeShader('wave')" aria-label="切换到波浪效果">波浪效果</button>
            <button @click="changeShader('noise')" aria-label="切换到噪声效果">噪声效果</button>
            <button @click="changeShader('gradient')" aria-label="切换到渐变效果">渐变效果</button>
          </nav>
        </div>
      </article>

      <!-- 模型加载 -->
      <article class="demo-card">
        <header class="demo-header">
          <h2>模型加载</h2>
          <button @click="showCode('model')" class="code-btn" aria-label="查看模型加载代码">查看代码</button>
        </header>
        <div class="demo-content">
          <div class="canvas-container" ref="modelContainer" role="img" aria-label="3D模型加载演示"></div>
          <div class="model-upload">
            <input 
              type="file" 
              accept=".glb,.gltf,.obj" 
              @change="handleModelUpload" 
              ref="modelInput"
              class="model-input"
              aria-label="选择3D模型文件"
            >
            <button @click="triggerModelUpload" class="upload-btn" aria-label="选择3D模型文件">选择3D模型文件</button>
            <div class="file-info" v-if="currentModelFile">
              当前文件: {{ currentModelFile.name }}
            </div>
          </div>
          <nav class="controls">
            <button @click="toggleModelAnimation" :disabled="!currentModel" aria-label="重置模型">重置模型</button>
          </nav>
        </div>
      </article>
    </section>

    <!-- 代码查看弹窗 -->
    <dialog v-if="showCodeModal" class="code-modal" role="dialog" aria-labelledby="code-modal-title">
      <div class="code-modal-content">
        <header class="code-modal-header">
          <h3 id="code-modal-title">{{ codeModalTitle }}</h3>
          <button class="close-btn" @click="closeCodeModal" aria-label="关闭代码弹窗">×</button>
        </header>
        <div class="code-modal-body">
          <pre><code>{{ currentCode }}</code></pre>
        </div>
      </div>
    </dialog>
  </main>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'
import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass'
import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'

// 场景状态
const isAnimating = ref(true)
const currentGeometry = ref('box')
const currentMaterial = ref('standard')
const currentLight = ref('point')

// 新增状态
const isCameraAnimating = ref(true)
const isParticleAnimating = ref(true)
const currentCamera = ref('perspective')
const currentEffect = ref('none')
const currentParticleType = ref('points')
const isAudioPlaying = ref(false)
const isModelAnimating = ref(true)
const currentAudioVisualization = ref('bars')
const currentShader = ref('wave')

// 容器引用
const basicGeometryContainer = ref(null)
const materialsContainer = ref(null)
const lightsContainer = ref(null)
const animationContainer = ref(null)
const cameraControlContainer = ref(null)
const postProcessingContainer = ref(null)
const particlesContainer = ref(null)
const physicsContainer = ref(null)
const audioContainer = ref(null)
const shaderContainer = ref(null)
const modelContainer = ref(null)

// 场景对象
let scenes = []
let cameras = []
let renderers = []
let controls = []
let meshes = []
let lights = []
let animationFrameId = null
let composers = []
let particleSystems = []
let physicsObjects = []
let audioAnalyser = null
let audioData = null
let shaderMaterial = null
let currentModel = null

// 代码查看相关状态
const showCodeModal = ref(false)
const codeModalTitle = ref('')
const currentCode = ref('')

// 音频相关状态
const audioInput = ref(null)
const audioSource = ref(null)
const audioContext = ref(null)

// 模型相关状态
const modelInput = ref(null)
const currentModelFile = ref(null)

// 着色器代码
const shaders = {
  wave: {
    vertex: `
      varying vec2 vUv;
      void main() {
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `,
    fragment: `
      uniform float time;
      varying vec2 vUv;
      void main() {
        vec2 uv = vUv;
        float wave = sin(uv.x * 10.0 + time) * 0.5 + 0.5;
        gl_FragColor = vec4(wave, wave * 0.5, 1.0, 1.0);
      }
    `
  },
  noise: {
    vertex: `
      varying vec2 vUv;
      void main() {
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `,
    fragment: `
      uniform float time;
      varying vec2 vUv;
      
      float random(vec2 st) {
        return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);
      }
      
      void main() {
        vec2 uv = vUv;
        float noise = random(uv + time);
        gl_FragColor = vec4(noise, noise * 0.5, 1.0, 1.0);
      }
    `
  },
  gradient: {
    vertex: `
      varying vec2 vUv;
      void main() {
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `,
    fragment: `
      uniform float time;
      varying vec2 vUv;
      void main() {
        vec2 uv = vUv;
        vec3 color1 = vec3(0.5, 0.0, 0.5);
        vec3 color2 = vec3(0.0, 0.5, 1.0);
        vec3 color = mix(color1, color2, sin(uv.x + time) * 0.5 + 0.5);
        gl_FragColor = vec4(color, 1.0);
      }
    `
  }
}

// 创建着色器材质
const createShaderMaterial = (type) => {
  return new THREE.ShaderMaterial({
    uniforms: {
      time: { value: 0 }
    },
    vertexShader: shaders[type].vertex,
    fragmentShader: shaders[type].fragment
  })
}

// 创建基础几何体
const createGeometry = (type) => {
  switch (type) {
    case 'box':
      return new THREE.BoxGeometry(1, 1, 1)
    case 'sphere':
      return new THREE.SphereGeometry(0.7, 32, 32)
    case 'torus':
      return new THREE.TorusGeometry(0.7, 0.3, 16, 100)
    default:
      return new THREE.BoxGeometry(1, 1, 1)
  }
}

// 创建材质
const createMaterial = (type) => {
  switch (type) {
    case 'standard':
      return new THREE.MeshStandardMaterial({
        color: 0x00ff88,
        metalness: 0.5,
        roughness: 0.5
      })
    case 'phong':
      return new THREE.MeshPhongMaterial({
        color: 0x00ff88,
        shininess: 100
      })
    case 'toon':
      return new THREE.MeshToonMaterial({
        color: 0x00ff88
      })
    default:
      return new THREE.MeshStandardMaterial({ color: 0x00ff88 })
  }
}

// 创建光源
const createLight = (type) => {
  switch (type) {
    case 'point':
      const pointLight = new THREE.PointLight(0xffffff, 1)
      pointLight.position.set(2, 2, 2)
      return pointLight
    case 'spot':
      const spotLight = new THREE.SpotLight(0xffffff, 1)
      spotLight.position.set(2, 5, 2)
      spotLight.angle = Math.PI / 6
      return spotLight
    case 'ambient':
      return new THREE.AmbientLight(0xffffff, 0.5)
    default:
      return new THREE.PointLight(0xffffff, 1)
  }
}

// 创建后期处理效果
const createEffect = (type, scene, camera, renderer) => {
  const composer = new EffectComposer(renderer)
  const renderPass = new RenderPass(scene, camera)
  composer.addPass(renderPass)

  switch (type) {
    case 'bloom':
      const bloomPass = new UnrealBloomPass(
        new THREE.Vector2(window.innerWidth, window.innerHeight),
        1.5, 0.4, 0.85
      )
      composer.addPass(bloomPass)
      break
    case 'outline':
      const outlinePass = new OutlinePass(
        new THREE.Vector2(window.innerWidth, window.innerHeight),
        scene,
        camera
      )
      outlinePass.edgeStrength = 3
      outlinePass.edgeGlow = 1
      outlinePass.edgeThickness = 1
      outlinePass.pulsePeriod = 0
      outlinePass.visibleEdgeColor.set('#ffffff')
      outlinePass.hiddenEdgeColor.set('#190a05')
      composer.addPass(outlinePass)
      break
  }

  return composer
}

// 创建物理对象
const createPhysicsObject = (type) => {
  let geometry, material, mesh
  
  if (type === 'sphere') {
    geometry = new THREE.SphereGeometry(0.5, 32, 32)
    material = new THREE.MeshStandardMaterial({ color: 0xff0000 })
    mesh = new THREE.Mesh(geometry, material)
  } else {
    geometry = new THREE.BoxGeometry(1, 1, 1)
    material = new THREE.MeshStandardMaterial({ color: 0x00ff00 })
    mesh = new THREE.Mesh(geometry, material)
  }
  
  // 设置初始位置
  mesh.position.set(
    (Math.random() - 0.5) * 5,
    Math.random() * 5 + 5,
    (Math.random() - 0.5) * 5
  )
  
  // 设置初始速度
  mesh.velocity = new THREE.Vector3(
    (Math.random() - 0.5) * 0.1,
    0,
    (Math.random() - 0.5) * 0.1
  )
  
  return mesh
}

// 创建粒子系统
const createParticleSystem = (type) => {
  const particles = new THREE.BufferGeometry()
  const particleCount = 1000
  const positions = new Float32Array(particleCount * 3)
  const colors = new Float32Array(particleCount * 3)

  for (let i = 0; i < particleCount * 3; i += 3) {
    positions[i] = (Math.random() - 0.5) * 10
    positions[i + 1] = (Math.random() - 0.5) * 10
    positions[i + 2] = (Math.random() - 0.5) * 10

    colors[i] = Math.random()
    colors[i + 1] = Math.random()
    colors[i + 2] = Math.random()
  }

  particles.setAttribute('position', new THREE.BufferAttribute(positions, 3))
  particles.setAttribute('color', new THREE.BufferAttribute(colors, 3))

  let material
  if (type === 'points') {
    material = new THREE.PointsMaterial({
      size: 0.1,
      vertexColors: true
    })
    return new THREE.Points(particles, material)
  } else {
    const sprite = new THREE.TextureLoader().load('/sprite.png')
    material = new THREE.PointsMaterial({
      size: 0.5,
      map: sprite,
      vertexColors: true,
      blending: THREE.AdditiveBlending
    })
    return new THREE.Points(particles, material)
  }
}

// 初始化音频可视化
const initAudioVisualization = () => {
  if (scenes[8]) {
    // 创建音频可视化几何体
    const geometry = new THREE.BufferGeometry()
    const positions = new Float32Array(128 * 3)
    geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
    
    const material = new THREE.LineBasicMaterial({ color: 0x00ff00 })
    const visualization = new THREE.LineSegments(geometry, material)
    scenes[8].add(visualization)
  }
}

// 处理音频文件上传
const handleAudioUpload = async (event) => {
  const file = event.target.files[0]
  if (!file) return

  try {
    // 如果已经存在音频上下文，先关闭它
    if (audioContext.value) {
      await audioContext.value.close()
    }

    // 创建新的音频上下文
    audioContext.value = new (window.AudioContext || window.webkitAudioContext)()
    audioAnalyser = audioContext.value.createAnalyser()
    audioAnalyser.fftSize = 256
    audioData = new Uint8Array(audioAnalyser.frequencyBinCount)

    // 创建音频源
    const arrayBuffer = await file.arrayBuffer()
    const audioBuffer = await audioContext.value.decodeAudioData(arrayBuffer)
    audioSource.value = audioContext.value.createBufferSource()
    audioSource.value.buffer = audioBuffer
    audioSource.value.connect(audioAnalyser)
    audioAnalyser.connect(audioContext.value.destination)

    // 初始化可视化
    initAudioVisualization()
    
    // 启用控制按钮
    isAudioPlaying.value = false
  } catch (error) {
    console.error('Error loading audio file:', error)
  }
}

// 音频播放控制
const toggleAudio = () => {
  if (!audioSource.value || !audioContext.value) return

  if (isAudioPlaying.value) {
    audioContext.value.suspend()
    isAudioPlaying.value = false
  } else {
    if (audioContext.value.state === 'suspended') {
      audioContext.value.resume()
    } else {
      // 重新创建音频源（因为音频源只能播放一次）
      const newSource = audioContext.value.createBufferSource()
      newSource.buffer = audioSource.value.buffer
      newSource.connect(audioAnalyser)
      audioSource.value = newSource
      newSource.start(0)
    }
    isAudioPlaying.value = true
  }
}

// 更新音频可视化
const updateAudioVisualization = () => {
  if (scenes[8] && audioAnalyser && isAudioPlaying.value) {
    audioAnalyser.getByteFrequencyData(audioData)
    
    const visualization = scenes[8].children.find(child => child instanceof THREE.LineSegments)
    if (visualization) {
      const positions = visualization.geometry.attributes.position.array
      
      if (currentAudioVisualization.value === 'bars') {
        // 柱状频谱
        for (let i = 0; i < audioData.length; i++) {
          const value = audioData[i] / 255
          const x = (i / audioData.length) * 4 - 2
          positions[i * 3] = x
          positions[i * 3 + 1] = value * 2
          positions[i * 3 + 2] = 0
        }
      } else {
        // 圆形频谱
        const radius = 2
        for (let i = 0; i < audioData.length; i++) {
          const value = audioData[i] / 255
          const angle = (i / audioData.length) * Math.PI * 2
          const x = Math.cos(angle) * (radius + value)
          const y = Math.sin(angle) * (radius + value)
          positions[i * 3] = x
          positions[i * 3 + 1] = y
          positions[i * 3 + 2] = 0
        }
      }
      
      visualization.geometry.attributes.position.needsUpdate = true
    }
  }
}

// 触发文件选择
const triggerAudioUpload = () => {
  audioInput.value.click()
}

// 动画循环
const animate = () => {
  requestAnimationFrame(animate)

  // 更新所有场景
  scenes.forEach((scene, index) => {
    if (!scene || !renderers[index] || !cameras[index] || !controls[index]) {
      return
    }

    // 更新控制器
    controls[index].update()

    // 更新动画
    if (meshes[index]) {
      if (index === 3 && isAnimating.value) { // 动画效果场景
        meshes[index].rotation.x += 0.01
        meshes[index].rotation.y += 0.01
      }
    }

    // 更新粒子系统
    if (particleSystems[index] && isParticleAnimating.value) {
      particleSystems[index].rotation.y += 0.001
    }

    // 更新物理效果
    if (index === 7) { // 物理效果场景
      physicsObjects.forEach(object => {
        if (object && object.velocity) {
          object.position.add(object.velocity)
          object.velocity.y -= 0.01 // 重力

          // 简单的碰撞检测
          if (object.position.y < -5) {
            object.position.y = -5
            object.velocity.y *= -0.5 // 反弹
          }
        }
      })
    }

    // 更新音频可视化
    if (index === 8) { // 音频可视化场景
      updateAudioVisualization()
    }

    // 更新着色器效果
    if (index === 9 && shaderMaterial) { // 着色器效果场景
      shaderMaterial.uniforms.time.value += 0.01
    }

    // 更新模型动画
    if (index === 10 && currentModel && isModelAnimating.value) {
      currentModel.rotation.y += 0.01
    }

    // 渲染场景
    if (composers[index]) {
      composers[index].render()
    } else {
      renderers[index].render(scene, cameras[index])
    }
  })
}

// 更改几何体
const changeGeometry = (type) => {
  currentGeometry.value = type
  if (meshes[0]) {
    const newGeometry = createGeometry(type)
    meshes[0].geometry.dispose()
    meshes[0].geometry = newGeometry
  }
}

// 更改材质
const changeMaterial = (type) => {
  currentMaterial.value = type
  if (meshes[1]) {
    const newMaterial = createMaterial(type)
    meshes[1].material.dispose()
    meshes[1].material = newMaterial
  }
}

// 更改光源
const changeLight = (type) => {
  currentLight.value = type
  if (scenes[2] && lights[2]) {
    scenes[2].remove(lights[2])
    lights[2] = createLight(type)
    scenes[2].add(lights[2])
  }
}

// 切换动画
const toggleAnimation = () => {
  isAnimating.value = !isAnimating.value
}

// 重置动画
const resetAnimation = () => {
  if (meshes[3]) {
    meshes[3].rotation.set(0, 0, 0)
  }
}

// 更改相机
const changeCamera = (type) => {
  currentCamera.value = type
  if (scenes[4]) {
    const container = cameraControlContainer.value
    const aspect = container.clientWidth / container.clientHeight
    
    if (type === 'perspective') {
      cameras[4] = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000)
    } else {
      const frustumSize = 10
      cameras[4] = new THREE.OrthographicCamera(
        frustumSize * aspect / -2,
        frustumSize * aspect / 2,
        frustumSize / 2,
        frustumSize / -2,
        0.1,
        1000
      )
    }
    cameras[4].position.z = 5
    controls[4].object = cameras[4]
  }
}

// 切换相机动画
const toggleCameraAnimation = () => {
  isCameraAnimating.value = !isCameraAnimating.value
}

// 更改后期处理效果
const changeEffect = (type) => {
  currentEffect.value = type
  if (scenes[5]) {
    composers[5] = createEffect(type, scenes[5], cameras[5], renderers[5])
  }
}

// 更改粒子类型
const changeParticleType = (type) => {
  currentParticleType.value = type
  if (scenes[6]) {
    const newParticleSystem = createParticleSystem(type)
    scenes[6].remove(particleSystems[6])
    particleSystems[6] = newParticleSystem
    scenes[6].add(particleSystems[6])
  }
}

// 切换粒子动画
const toggleParticleAnimation = () => {
  isParticleAnimating.value = !isParticleAnimating.value
}

// 添加物理对象
const addPhysicsObject = (type) => {
  if (scenes[7]) {
    const object = createPhysicsObject(type)
    scenes[7].add(object)
    physicsObjects.push(object)
  }
}

// 重置物理场景
const resetPhysics = () => {
  if (scenes[7]) {
    physicsObjects.forEach(object => {
      scenes[7].remove(object)
      object.geometry.dispose()
      object.material.dispose()
    })
    physicsObjects = []
  }
}

// 更改音频可视化类型
const changeAudioVisualization = (type) => {
  currentAudioVisualization.value = type
}

// 更改着色器效果
const changeShader = (type) => {
  if (meshes[9]) {
    const newMaterial = createShaderMaterial(type)
    meshes[9].material.dispose()
    meshes[9].material = newMaterial
    shaderMaterial = newMaterial
  }
}

// 处理模型文件上传
const handleModelUpload = async (event) => {
  const file = event.target.files[0]
  if (!file) return

  currentModelFile.value = file
  const fileExtension = file.name.split('.').pop().toLowerCase()
  
  try {
    // 根据文件类型选择加载器
    let loader
    if (fileExtension === 'glb' || fileExtension === 'gltf') {
      loader = new GLTFLoader()
      const dracoLoader = new DRACOLoader()
      dracoLoader.setDecoderPath('/draco/')
      loader.setDRACOLoader(dracoLoader)
    } else if (fileExtension === 'obj') {
      loader = new OBJLoader()
    } else {
      throw new Error('不支持的文件格式')
    }

    // 加载模型
    const arrayBuffer = await file.arrayBuffer()
    const model = await loader.parseAsync(arrayBuffer)
    const modelObject = fileExtension === 'obj' ? model : model.scene

    // 移除旧模型
    if (currentModel) {
      scenes[10].remove(currentModel)
      currentModel.traverse(child => {
        if (child.geometry) child.geometry.dispose()
        if (child.material) child.material.dispose()
      })
    }

    // 调整模型大小和位置
    const box = new THREE.Box3().setFromObject(modelObject)
    const size = box.getSize(new THREE.Vector3())
    const center = box.getCenter(new THREE.Vector3())
    
    const maxDim = Math.max(size.x, size.y, size.z)
    const scale = 2 / maxDim
    modelObject.scale.setScalar(scale)
    
    // 重置位置并居中
    modelObject.position.set(0, 0, 0)
    modelObject.position.sub(center.multiplyScalar(scale))
    
    // 重置旋转
    modelObject.rotation.set(0, 0, 0)
    
    // 添加到场景
    scenes[10].add(modelObject)
    currentModel = modelObject

    // 重置动画状态
    isModelAnimating.value = true
  } catch (error) {
    console.error('加载模型时出错:', error)
    // 可以在这里添加错误提示UI
  }
}

// 切换模型动画
const toggleModelAnimation = () => {
  isModelAnimating.value = !isModelAnimating.value
}

// 重置模型
const resetModel = () => {
  if (currentModel) {
    currentModel.rotation.set(0, 0, 0)
    currentModel.position.set(0, 0, 0)
    currentModel.scale.setScalar(1)
  }
}

// 触发模型文件选择
const triggerModelUpload = () => {
  modelInput.value.click()
}

// 代码示例
const codeExamples = {
  geometry: `// 创建基础几何体
const createGeometry = (type) => {
  switch (type) {
    case 'box':
      return new THREE.BoxGeometry(1, 1, 1)
    case 'sphere':
      return new THREE.SphereGeometry(0.7, 32, 32)
    case 'torus':
      return new THREE.TorusGeometry(0.7, 0.3, 16, 100)
    default:
      return new THREE.BoxGeometry(1, 1, 1)
  }
}`,
  
  material: `// 创建材质
const createMaterial = (type) => {
  switch (type) {
    case 'standard':
      return new THREE.MeshStandardMaterial({
        color: 0x00ff88,
        metalness: 0.5,
        roughness: 0.5
      })
    case 'phong':
      return new THREE.MeshPhongMaterial({
        color: 0x00ff88,
        shininess: 100
      })
    case 'toon':
      return new THREE.MeshToonMaterial({
        color: 0x00ff88
      })
    default:
      return new THREE.MeshStandardMaterial({ color: 0x00ff88 })
  }
}`,
  
  light: `// 创建光源
const createLight = (type) => {
  switch (type) {
    case 'point':
      const pointLight = new THREE.PointLight(0xffffff, 1)
      pointLight.position.set(2, 2, 2)
      return pointLight
    case 'spot':
      const spotLight = new THREE.SpotLight(0xffffff, 1)
      spotLight.position.set(2, 5, 2)
      spotLight.angle = Math.PI / 6
      return spotLight
    case 'ambient':
      return new THREE.AmbientLight(0xffffff, 0.5)
    default:
      return new THREE.PointLight(0xffffff, 1)
  }
}`,
  
  animation: `// 动画循环
const animate = () => {
  if (!isAnimating.value) return

  animationFrameId = requestAnimationFrame(animate)

  // 更新所有场景
  meshes.forEach((mesh, index) => {
    if (mesh) {
      mesh.rotation.x += 0.01
      mesh.rotation.y += 0.01
    }
  })
}`,
  
  camera: `// 更改相机类型
const changeCamera = (type) => {
  currentCamera.value = type
  if (scenes[4]) {
    const container = cameraControlContainer.value
    const aspect = container.clientWidth / container.clientHeight
    
    if (type === 'perspective') {
      cameras[4] = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000)
    } else {
      const frustumSize = 10
      cameras[4] = new THREE.OrthographicCamera(
        frustumSize * aspect / -2,
        frustumSize * aspect / 2,
        frustumSize / 2,
        frustumSize / -2,
        0.1,
        1000
      )
    }
    cameras[4].position.z = 5
  }
}`,
  
  postprocessing: `// 创建后期处理效果
const createEffect = (type, scene, camera, renderer) => {
  const composer = new EffectComposer(renderer)
  const renderPass = new RenderPass(scene, camera)
  composer.addPass(renderPass)

  switch (type) {
    case 'bloom':
      const bloomPass = new UnrealBloomPass(
        new THREE.Vector2(window.innerWidth, window.innerHeight),
        1.5, 0.4, 0.85
      )
      composer.addPass(bloomPass)
      break
    case 'outline':
      const outlinePass = new OutlinePass(
        new THREE.Vector2(window.innerWidth, window.innerHeight),
        scene,
        camera
      )
      outlinePass.edgeStrength = 3
      outlinePass.edgeGlow = 1
      outlinePass.edgeThickness = 1
      outlinePass.pulsePeriod = 0
      outlinePass.visibleEdgeColor.set('#ffffff')
      outlinePass.hiddenEdgeColor.set('#190a05')
      composer.addPass(outlinePass)
      break
  }

  return composer
}`,
  
  particles: `// 创建粒子系统
const createParticleSystem = (type) => {
  const particles = new THREE.BufferGeometry()
  const particleCount = 1000
  const positions = new Float32Array(particleCount * 3)
  const colors = new Float32Array(particleCount * 3)

  for (let i = 0; i < particleCount * 3; i += 3) {
    positions[i] = (Math.random() - 0.5) * 10
    positions[i + 1] = (Math.random() - 0.5) * 10
    positions[i + 2] = (Math.random() - 0.5) * 10

    colors[i] = Math.random()
    colors[i + 1] = Math.random()
    colors[i + 2] = Math.random()
  }

  particles.setAttribute('position', new THREE.BufferAttribute(positions, 3))
  particles.setAttribute('color', new THREE.BufferAttribute(colors, 3))

  let material
  if (type === 'points') {
    material = new THREE.PointsMaterial({
      size: 0.1,
      vertexColors: true
    })
    return new THREE.Points(particles, material)
  } else {
    const sprite = new THREE.TextureLoader().load('/sprite.png')
    material = new THREE.PointsMaterial({
      size: 0.5,
      map: sprite,
      vertexColors: true,
      blending: THREE.AdditiveBlending
    })
    return new THREE.Points(particles, material)
  }
}`,
  
  physics: `// 创建物理对象
const createPhysicsObject = (type) => {
  let geometry, material, mesh
  
  if (type === 'sphere') {
    geometry = new THREE.SphereGeometry(0.5, 32, 32)
    material = new THREE.MeshStandardMaterial({ color: 0xff0000 })
    mesh = new THREE.Mesh(geometry, material)
  } else {
    geometry = new THREE.BoxGeometry(1, 1, 1)
    material = new THREE.MeshStandardMaterial({ color: 0x00ff00 })
    mesh = new THREE.Mesh(geometry, material)
  }
  
  // 设置初始位置
  mesh.position.set(
    (Math.random() - 0.5) * 5,
    Math.random() * 5 + 5,
    (Math.random() - 0.5) * 5
  )
  
  // 设置初始速度
  mesh.velocity = new THREE.Vector3(
    (Math.random() - 0.5) * 0.1,
    0,
    (Math.random() - 0.5) * 0.1
  )
  
  return mesh
}`,
  
  audio: `// 处理音频文件上传
const handleAudioUpload = async (event) => {
  const file = event.target.files[0]
  if (!file) return

  try {
    // 如果已经存在音频上下文，先关闭它
    if (audioContext.value) {
      await audioContext.value.close()
    }

    // 创建新的音频上下文
    audioContext.value = new (window.AudioContext || window.webkitAudioContext)()
    audioAnalyser = audioContext.value.createAnalyser()
    audioAnalyser.fftSize = 256
    audioData = new Uint8Array(audioAnalyser.frequencyBinCount)

    // 创建音频源
    const arrayBuffer = await file.arrayBuffer()
    const audioBuffer = await audioContext.value.decodeAudioData(arrayBuffer)
    audioSource.value = audioContext.value.createBufferSource()
    audioSource.value.buffer = audioBuffer
    audioSource.value.connect(audioAnalyser)
    audioAnalyser.connect(audioContext.value.destination)

    // 初始化可视化
    initAudioVisualization()
    
    // 启用控制按钮
    isAudioPlaying.value = false
  } catch (error) {
    console.error('Error loading audio file:', error)
  }
}

// 音频播放控制
const toggleAudio = () => {
  if (!audioSource.value || !audioContext.value) return

  if (isAudioPlaying.value) {
    audioContext.value.suspend()
    isAudioPlaying.value = false
  } else {
    if (audioContext.value.state === 'suspended') {
      audioContext.value.resume()
    } else {
      // 重新创建音频源（因为音频源只能播放一次）
      const newSource = audioContext.value.createBufferSource()
      newSource.buffer = audioSource.value.buffer
      newSource.connect(audioAnalyser)
      audioSource.value = newSource
      newSource.start(0)
    }
    isAudioPlaying.value = true
  }
}

// 更新音频可视化
const updateAudioVisualization = () => {
  if (scenes[8] && audioAnalyser && isAudioPlaying.value) {
    audioAnalyser.getByteFrequencyData(audioData)
    
    const visualization = scenes[8].children.find(child => child instanceof THREE.LineSegments)
    if (visualization) {
      const positions = visualization.geometry.attributes.position.array
      
      if (currentAudioVisualization.value === 'bars') {
        // 柱状频谱
        for (let i = 0; i < audioData.length; i++) {
          const value = audioData[i] / 255
          const x = (i / audioData.length) * 4 - 2
          positions[i * 3] = x
          positions[i * 3 + 1] = value * 2
          positions[i * 3 + 2] = 0
        }
      } else {
        // 圆形频谱
        const radius = 2
        for (let i = 0; i < audioData.length; i++) {
          const value = audioData[i] / 255
          const angle = (i / audioData.length) * Math.PI * 2
          const x = Math.cos(angle) * (radius + value)
          const y = Math.sin(angle) * (radius + value)
          positions[i * 3] = x
          positions[i * 3 + 1] = y
          positions[i * 3 + 2] = 0
        }
      }
      
      visualization.geometry.attributes.position.needsUpdate = true
    }
  }
}

// 触发文件选择
const triggerAudioUpload = () => {
  audioInput.value.click()
}

// 初始化音频可视化
const initAudioVisualization = () => {
  if (scenes[8]) {
    // 创建音频可视化几何体
    const geometry = new THREE.BufferGeometry()
    const positions = new Float32Array(128 * 3)
    geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
    
    const material = new THREE.LineBasicMaterial({ color: 0x00ff00 })
    const visualization = new THREE.LineSegments(geometry, material)
    scenes[8].add(visualization)
  }
}`,
  
  shader: `// 创建着色器材质
const createShaderMaterial = (type) => {
  return new THREE.ShaderMaterial({
    uniforms: {
      time: { value: 0 }
    },
    vertexShader: shaders[type].vertex,
    fragmentShader: shaders[type].fragment
  })
}

// 着色器代码示例
const shaders = {
  wave: {
    vertex: \`
      varying vec2 vUv;
      void main() {
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    \`,
    fragment: \`
      uniform float time;
      varying vec2 vUv;
      void main() {
        vec2 uv = vUv;
        float wave = sin(uv.x * 10.0 + time) * 0.5 + 0.5;
        gl_FragColor = vec4(wave, wave * 0.5, 1.0, 1.0);
      }
    \`
  },
  noise: {
    vertex: \`
      varying vec2 vUv;
      void main() {
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    \`,
    fragment: \`
      uniform float time;
      varying vec2 vUv;
      
      float random(vec2 st) {
        return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);
      }
      
      void main() {
        vec2 uv = vUv;
        float noise = random(uv + time);
        gl_FragColor = vec4(noise, noise * 0.5, 1.0, 1.0);
      }
    \`
  },
  gradient: {
    vertex: \`
      varying vec2 vUv;
      void main() {
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    \`,
    fragment: \`
      uniform float time;
      varying vec2 vUv;
      void main() {
        vec2 uv = vUv;
        vec3 color1 = vec3(0.5, 0.0, 0.5);
        vec3 color2 = vec3(0.0, 0.5, 1.0);
        vec3 color = mix(color1, color2, sin(uv.x + time) * 0.5 + 0.5);
        gl_FragColor = vec4(color, 1.0);
      }
    \`
  }
}`,
  
  model: `// 处理模型文件上传
const handleModelUpload = async (event) => {
  const file = event.target.files[0]
  if (!file) return

  const fileExtension = file.name.split('.').pop().toLowerCase()
  
  try {
    // 根据文件类型选择加载器
    let loader
    if (fileExtension === 'glb' || fileExtension === 'gltf') {
      loader = new GLTFLoader()
      const dracoLoader = new DRACOLoader()
      dracoLoader.setDecoderPath('/draco/')
      loader.setDRACOLoader(dracoLoader)
    } else if (fileExtension === 'obj') {
      loader = new OBJLoader()
    }

    // 加载模型
    const arrayBuffer = await file.arrayBuffer()
    const model = await loader.parseAsync(arrayBuffer)
    const modelObject = fileExtension === 'obj' ? model : model.scene

    // 调整模型大小和位置
    const box = new THREE.Box3().setFromObject(modelObject)
    const size = box.getSize(new THREE.Vector3())
    const center = box.getCenter(new THREE.Vector3())
    
    const maxDim = Math.max(size.x, size.y, size.z)
    const scale = 2 / maxDim
    modelObject.scale.setScalar(scale)
    
    modelObject.position.sub(center.multiplyScalar(scale))
    
    scenes[10].add(modelObject)
  } catch (error) {
    console.error('Error loading model:', error)
  }
}`
}

// 显示代码
const showCode = (type) => {
  codeModalTitle.value = {
    geometry: '基础几何体代码',
    material: '材质效果代码',
    light: '光照效果代码',
    animation: '动画效果代码',
    camera: '相机控制代码',
    postprocessing: '后期处理代码',
    particles: '粒子系统代码',
    physics: '物理效果代码',
    audio: '音频可视化代码',
    shader: '着色器效果代码',
    model: '模型加载代码'
  }[type]
  
  currentCode.value = codeExamples[type]
  showCodeModal.value = true
}

// 关闭代码弹窗
const closeCodeModal = () => {
  showCodeModal.value = false
}

// 初始化场景
const initScene = (container, index) => {
  if (!container) return null

  // 创建场景
  const scene = new THREE.Scene()
  scene.background = new THREE.Color(0x1a1a1a)
  scenes[index] = scene

  // 创建相机
  const camera = new THREE.PerspectiveCamera(75, container.clientWidth / container.clientHeight, 0.1, 1000)
  camera.position.z = 5
  cameras[index] = camera

  // 创建渲染器
  const renderer = new THREE.WebGLRenderer({ antialias: true })
  renderer.setSize(container.clientWidth, container.clientHeight)
  renderer.setPixelRatio(window.devicePixelRatio)
  container.appendChild(renderer.domElement)
  renderers[index] = renderer

  // 创建控制器
  const control = new OrbitControls(camera, renderer.domElement)
  control.enableDamping = true
  controls[index] = control

  // 添加环境光
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
  scene.add(ambientLight)

  // 添加平行光
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
  directionalLight.position.set(5, 5, 5)
  scene.add(directionalLight)

  // 根据不同的演示类型添加不同的模型
  switch (index) {
    case 0: // 基础几何体
      const geometry = createGeometry('box')
      const material = createMaterial('standard')
      const mesh = new THREE.Mesh(geometry, material)
      scene.add(mesh)
      meshes[index] = mesh
      break
    case 1: // 材质效果
      const materialMesh = new THREE.Mesh(
        new THREE.BoxGeometry(1, 1, 1),
        createMaterial('standard')
      )
      scene.add(materialMesh)
      meshes[index] = materialMesh
      break
    case 2: // 光照效果
      const lightMesh = new THREE.Mesh(
        new THREE.SphereGeometry(0.7, 32, 32),
        new THREE.MeshStandardMaterial({ color: 0x00ff88 })
      )
      scene.add(lightMesh)
      meshes[index] = lightMesh
      lights[index] = createLight('point')
      scene.add(lights[index])
      break
    case 3: // 动画效果
      const animMesh = new THREE.Mesh(
        new THREE.TorusGeometry(0.7, 0.3, 16, 100),
        new THREE.MeshStandardMaterial({ color: 0x00ff88 })
      )
      scene.add(animMesh)
      meshes[index] = animMesh
      break
    case 4: // 相机控制
      const cameraMesh = new THREE.Mesh(
        new THREE.BoxGeometry(1, 1, 1),
        new THREE.MeshStandardMaterial({ color: 0x00ff88 })
      )
      scene.add(cameraMesh)
      meshes[index] = cameraMesh
      break
    case 5: // 后期处理
      const postMesh = new THREE.Mesh(
        new THREE.SphereGeometry(0.7, 32, 32),
        new THREE.MeshStandardMaterial({ color: 0x00ff88 })
      )
      scene.add(postMesh)
      meshes[index] = postMesh
      composers[index] = createEffect('none', scene, camera, renderer)
      break
    case 6: // 粒子系统
      const particleSystem = createParticleSystem('points')
      scene.add(particleSystem)
      particleSystems[index] = particleSystem
      break
    case 7: // 物理效果
      const physicsMesh = new THREE.Mesh(
        new THREE.BoxGeometry(1, 1, 1),
        new THREE.MeshStandardMaterial({ color: 0x00ff88 })
      )
      scene.add(physicsMesh)
      meshes[index] = physicsMesh
      break
    case 8: // 音频可视化
      initAudioVisualization()
      break
    case 9: // 着色器效果
      const shaderMesh = new THREE.Mesh(
        new THREE.PlaneGeometry(2, 2),
        createShaderMaterial('wave')
      )
      scene.add(shaderMesh)
      meshes[index] = shaderMesh
      break
    case 10: // 模型加载
      // 移除初始占位模型，保持场景为空
      break
  }

  return { scene, camera, renderer, control }
}

// 初始化所有演示
onMounted(() => {
  // 初始化所有场景
  const containers = [
    basicGeometryContainer.value,
    materialsContainer.value,
    lightsContainer.value,
    animationContainer.value,
    cameraControlContainer.value,
    postProcessingContainer.value,
    particlesContainer.value,
    physicsContainer.value,
    audioContainer.value,
    shaderContainer.value,
    modelContainer.value
  ]

  containers.forEach((container, index) => {
    if (container) {
      initScene(container, index)
    }
  })

  // 启动动画循环
  animate()

  // 监听窗口大小变化
  window.addEventListener('resize', handleResize)
})

// 处理窗口大小变化
const handleResize = () => {
  cameras.forEach((camera, index) => {
    const container = [
      basicGeometryContainer.value,
      materialsContainer.value,
      lightsContainer.value,
      animationContainer.value,
      cameraControlContainer.value,
      postProcessingContainer.value,
      particlesContainer.value,
      physicsContainer.value,
      audioContainer.value,
      shaderContainer.value,
      modelContainer.value
    ][index]

    if (container && camera && renderers[index]) {
      const width = container.clientWidth
      const height = container.clientHeight
      
      camera.aspect = width / height
      camera.updateProjectionMatrix()
      
      renderers[index].setSize(width, height)
    }
  })
}

// 清理资源
onBeforeUnmount(() => {
  window.removeEventListener('resize', handleResize)
  
  if (animationFrameId !== null) {
    cancelAnimationFrame(animationFrameId)
  }

  // 清理Three.js资源
  scenes.forEach((scene, index) => {
    if (meshes[index]) {
      meshes[index].geometry.dispose()
      meshes[index].material.dispose()
    }
    if (renderers[index]) {
      renderers[index].dispose()
    }
  })

  composers.forEach(composer => {
    if (composer) {
      composer.dispose()
    }
  })

  if (audioAnalyser) {
    audioAnalyser.disconnect()
  }
  
  if (currentModel) {
    currentModel.traverse(child => {
      if (child.geometry) child.geometry.dispose()
      if (child.material) child.material.dispose()
    })
  }

  if (audioContext.value) {
    audioContext.value.close()
  }
  
  if (audioSource.value) {
    audioSource.value.disconnect()
  }
})
</script>

<style scoped>
.threejs-demo {
  padding: 2rem;
}

.section-title {
  font-size: 2.5rem;
  margin-bottom: 2rem;
  text-align: center;
  background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.demo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 2rem;
}

.demo-card {
  background: rgba(0, 0, 0, 0.3);
  border-radius: 15px;
  padding: 1.5rem;
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.demo-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
}

.demo-header h2 {
  margin: 0;
  color: var(--primary-color);
}

.code-btn {
  padding: 0.3rem 0.8rem;
  font-size: 0.9rem;
  background: linear-gradient(45deg, var(--secondary-color), var(--primary-color));
  color: white;
  font-weight: bold;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  transition: all 0.3s ease;
}

.code-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 5px 15px rgba(0, 255, 136, 0.2);
}

.demo-content {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.canvas-container {
  aspect-ratio: 16/9;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 10px;
  overflow: hidden;
}

.controls {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

button {
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 5px;
  background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
  color: var(--text-color);
  cursor: pointer;
  transition: all 0.3s ease;
}

button:hover {
  transform: translateY(-2px);
  box-shadow: 0 5px 15px rgba(0, 255, 136, 0.2);
}

.code-modal {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.8);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.code-modal-content {
  background: var(--background-color);
  border-radius: 15px;
  width: 80%;
  max-width: 800px;
  max-height: 80vh;
  overflow: hidden;
  border: 1px solid var(--primary-color);
}

.code-modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem;
  background: rgba(0, 0, 0, 0.3);
  border-bottom: 1px solid var(--primary-color);
}

.code-modal-header h3 {
  margin: 0;
  color: var(--primary-color);
}

.close-btn {
  background: none;
  border: none;
  color: var(--text-color);
  font-size: 1.5rem;
  cursor: pointer;
  padding: 0.5rem;
}

.code-modal-body {
  padding: 1rem;
  overflow-y: auto;
  max-height: calc(80vh - 4rem);
}

.code-modal-body pre {
  margin: 0;
  padding: 1rem;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 8px;
  overflow-x: auto;
}

.code-modal-body code {
  font-family: 'Fira Code', monospace;
  color: var(--text-color);
  line-height: 1.5;
}

.audio-upload {
  margin: 1rem 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}

.audio-input {
  display: none;
}

.upload-btn {
  background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
  color: white;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  transition: all 0.3s ease;
}

.upload-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 5px 15px rgba(0, 255, 136, 0.2);
}

button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none !important;
  box-shadow: none !important;
}

.model-upload {
  margin: 1rem 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}

.model-input {
  display: none;
}

.file-info {
  font-size: 0.9rem;
  color: var(--text-color);
  opacity: 0.8;
  margin-top: 0.5rem;
}

@media (max-width: 768px) {
  .threejs-demo {
    padding: 1rem;
  }

  .section-title {
    font-size: 2rem;
  }

  .demo-grid {
    grid-template-columns: 1fr;
  }

  .controls {
    flex-direction: column;
  }

  button {
    width: 100%;
  }

  .code-modal-content {
    width: 95%;
  }
  
  .code-modal-body {
    font-size: 0.9rem;
  }

  .demo-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
  }
  
  .code-btn {
    width: 100%;
  }
}
</style> 